/**
 * ProtoActor-TS 性能测试示例
 * 
 * 此示例演示了 ProtoActor-TS 的基本 Actor 模型功能，
 * 创建了一些简单的 Actor 并发送消息，
 * 并提供了压力测试功能来评估性能。
 * 
 * 运行方法:
 * ```
 * bun run examples/simple-actor-demo.ts
 * ```
 * 
 * 运行压力测试:
 * ```
 * bun run examples/simple-actor-demo.ts benchmark
 * ```
 */

// 导入必要的包
// 使用绝对导入路径以避免可能的问题
import { Actor } from '../src/actor/actor';
import { PID } from '../src/actor/pid';
import { ActorSystem } from '../src/actor/actorSystem';
import { Props } from '../src/actor/props';
import { Context } from '../src/actor/context';
import { performance } from 'perf_hooks';

// 简单的问候 Actor
class GreetingActor implements Actor {
  private greetingCount = 0;
  
  receive(context: Context): void {
    const message = context.message();
    
    if (typeof message === 'string') {
      this.greetingCount++;
      
      // 在非压测模式下打印消息
      if (!message.startsWith('benchmark_')) {
        console.log(`GreetingActor 收到消息: ${message}`);
        console.log(`收到问候: ${message}`);
        console.log(`问候计数: ${this.greetingCount}`);
      }
    }
  }
}

// 数学运算 Actor
class MathActor implements Actor {
  private operationCount = 0;
  
  receive(context: Context): void {
    const message = context.message();
    
    if (typeof message === 'object' && message !== null) {
      const msg = message as any;
      
      if (msg.operation === 'add' && typeof msg.a === 'number' && typeof msg.b === 'number') {
        this.operationCount++;
        const result = msg.a + msg.b;
        
        // 在非压测模式下打印消息
        if (!msg.benchmark) {
          console.log(`MathActor 收到消息:`, message);
          console.log(`加法运算: ${msg.a} + ${msg.b} = ${result}`);
          console.log(`运算计数: ${this.operationCount}`);
        }
      }
    }
  }
}

// 性能统计 Actor
class BenchmarkActor implements Actor {
  private messageCount = 0;
  private startTime = 0;
  private totalMessages = 0;
  private completed = false;
  
  receive(context: Context): void {
    const message = context.message();
    
    if (typeof message === 'object' && message !== null) {
      const msg = message as any;
      
      if (msg.type === 'start') {
        // 开始测试
        this.startTime = performance.now();
        this.messageCount = 0;
        this.totalMessages = msg.totalMessages;
        this.completed = false;
        console.log(`开始压测 - 目标消息量: ${this.totalMessages}条`);
      }
      else if (msg.type === 'message') {
        // 记录消息
        this.messageCount++;
        
        // 达到目标消息数量时完成测试
        if (this.messageCount === this.totalMessages && !this.completed) {
          this.completed = true;
          const endTime = performance.now();
          const duration = endTime - this.startTime;
          const messagesPerSecond = Math.floor((this.messageCount / duration) * 1000);
          
          console.log(`\n===== 压测结果 =====`);
          console.log(`总处理消息: ${this.messageCount}条`);
          console.log(`总耗时: ${duration.toFixed(2)}毫秒`);
          console.log(`吞吐量: ${messagesPerSecond}条/秒`);
          console.log(`平均延迟: ${(duration / this.messageCount).toFixed(3)}毫秒/消息`);
          console.log(`===================\n`);
        }
      }
    }
  }
}

// 主函数
async function main() {
  // 检查是否为压测模式
  const isBenchmark = process.argv.includes('benchmark');
  
  if (isBenchmark) {
    await runBenchmark();
  } else {
    await runDemo();
  }
}

// 示例演示
async function runDemo() {
  console.log('=== 简单 Actor 示例开始 ===');
  
  // 创建 Actor 系统
  const system = new ActorSystem();
  console.log('Actor 系统已创建');
  
  // 创建问候 Actor
  const greetingProps = Props.fromProducer(() => new GreetingActor());
  const greetingPid = system.root.spawn(greetingProps);
  console.log(`问候 Actor 已创建: ${greetingPid.toString()}`);
  
  // 创建数学 Actor
  const mathProps = Props.fromProducer(() => new MathActor());
  const mathPid = system.root.spawn(mathProps);
  console.log(`数学 Actor 已创建: ${mathPid.toString()}`);
  
  // 发送消息给问候 Actor
  console.log('\n向问候 Actor 发送消息:');
  system.root.send(greetingPid, '你好，Actor 世界！');
  system.root.send(greetingPid, '再次问候！');
  
  // 发送消息给数学 Actor
  console.log('\n向数学 Actor 发送消息:');
  system.root.send(mathPid, { operation: 'add', a: 10, b: 5 });
  
  // 等待一段时间让消息处理完成
  await new Promise(resolve => setTimeout(resolve, 100));
  
  // 停止 Actor 系统
  console.log('\n停止 Actor 系统...');
  await system.terminate();
  
  console.log('=== 简单 Actor 示例结束 ===');
}

// 运行压力测试
async function runBenchmark() {
  console.log('=== Actor 性能压测开始 ===');
  
  // 创建 Actor 系统
  const system = new ActorSystem();
  console.log('Actor 系统已创建');
  
  // 定义测试配置
  const tests = [
    { name: '单 Actor 消息吞吐量测试 (10万条消息)', messageCount: 100000, actorCount: 1 },
    { name: '多 Actor 消息吞吐量测试 (10个Actor各1万条)', messageCount: 10000, actorCount: 10 }
  ];
  
  // 运行每个测试
  for (const test of tests) {
    try {
      console.log(`\n运行测试: ${test.name}`);
      await runSingleTest(system, test);
    } catch (error) {
      console.error(`测试执行失败: ${error.message}`);
    }
    
    // 等待一下确保资源释放
    await new Promise(resolve => setTimeout(resolve, 500));
  }
  
  // 停止 Actor 系统
  console.log('\n所有测试完成，停止 Actor 系统...');
  await system.terminate();
  
  console.log('=== Actor 性能压测结束 ===');
}

// 单个测试函数
async function runSingleTest(system: ActorSystem, testConfig: any) {
  // 创建 benchmark actor 用于统计性能
  const benchmarkProps = Props.fromProducer(() => new BenchmarkActor());
  const benchmarkPid = system.root.spawn(benchmarkProps);
  
  // 创建测试用的 actor 数组
  const actorPids: PID[] = [];
  for (let i = 0; i < testConfig.actorCount; i++) {
    // 默认使用 GreetingActor 进行测试
    const props = Props.fromProducer(() => new GreetingActor());
    const pid = system.root.spawn(props);
    actorPids.push(pid);
  }
  
  // 计算总消息数
  const totalMessages = testConfig.messageCount * testConfig.actorCount;
  
  // 通知 benchmark actor 开始测试
  system.root.send(benchmarkPid, { 
    type: 'start', 
    totalMessages: totalMessages 
  });
  
  console.log(`发送 ${totalMessages} 条消息...`);
  
  // 发送测试消息
  for (let actorIndex = 0; actorIndex < testConfig.actorCount; actorIndex++) {
    const actorPid = actorPids[actorIndex];
    
    for (let i = 0; i < testConfig.messageCount; i++) {
      // 发送消息到目标 actor
      system.root.send(actorPid, `benchmark_${actorIndex}_${i}`);
      
      // 通知 benchmark actor 已发送消息
      system.root.send(benchmarkPid, { type: 'message' });
    }
  }
  
  // 等待测试完成
  await new Promise(resolve => setTimeout(resolve, 1000));
}

// 运行主函数
main().catch(error => {
  console.error('运行时错误:', error);
}); 